package dongchel.vrp.immunes;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import dongchel.vrp.data.LoadData;
import dongchel.vrp.entity.City;
import dongchel.vrp.entity.GlobalInformation;
import dongchel.vrp.entity.Route;
import dongchel.vrp.entity.Solution;
import dongchel.vrp.view.ShowSolution;

public class LocalSearch {
	public void interRouteMove(Solution solution, int pattern) {
		//inter-route movements
		//System.out.println("------------inter-route search------------");
		if(pattern==1) {
			//Shift(1,0)
			//System.out.println("Shift(1,0): ");
			int i = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			int j = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			while(j==i) {
				j = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			}
			int k = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-2)+1);
			int l = (int)Math.floor(Math.random()*(solution.getRouteList().get(j).getCityList().size()-1)+1);
		
			City cityk = solution.getRouteList().get(i).getCityList().get(k);
			solution.getRouteList().get(i).getCityList().remove(k);
			solution.getRouteList().get(j).getCityList().add(l, cityk);
			int jId = solution.getRouteList().get(j).getId();
			solution.getRouteList().get(i).refreshPD();
			for (int idc=0;idc<solution.getRouteList().size();idc++) {
				if(solution.getRouteList().get(idc).getId() == jId) {
					solution.getRouteList().get(idc).refreshPD();
					break;
				}
			}
			
		}
		if(pattern==2) {
			//Swap(1,1)
			//System.out.println("Swap(1,1):");
			int i = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			int j = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			while(i==j) {
				j = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			}
			int ki = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-2)+1);
			int kj = (int)Math.floor(Math.random()*(solution.getRouteList().get(j).getCityList().size()-2)+1);
			City cityi = solution.getRouteList().get(i).getCityList().get(ki);
			City cityj = solution.getRouteList().get(j).getCityList().get(kj);
			
			solution.getRouteList().get(i).getCityList().set(ki, cityj);
			solution.getRouteList().get(j).getCityList().set(kj, cityi);
			int jId = solution.getRouteList().get(j).getId();
			solution.getRouteList().get(i).refreshPD();
			for (int idc=0;idc<solution.getRouteList().size();idc++) {
				if(solution.getRouteList().get(idc).getId() == jId) {
					solution.getRouteList().get(idc).refreshPD();
					break;
				}
			}
		}
		if(pattern==3) {
			//Shift(2,0)
			//System.out.println("Shift(2,0):");
			int i = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			while(solution.getRouteList().get(i).getCityList().size()<4){
				i = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			}
			int j = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			while(j==i) {
				j = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			}
			int k = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-3)+1);
			int l = (int)Math.floor(Math.random()*(solution.getRouteList().get(j).getCityList().size()-1)+1);
			City cityk = solution.getRouteList().get(i).getCityList().get(k);
			City cityK = solution.getRouteList().get(i).getCityList().get(k+1);
						
			solution.getRouteList().get(i).getCityList().remove(k);
			solution.getRouteList().get(i).getCityList().remove(k);
			solution.getRouteList().get(j).getCityList().add(l, cityk);
			solution.getRouteList().get(j).getCityList().add(l+1, cityK);
			int jId = solution.getRouteList().get(j).getId();
			solution.getRouteList().get(i).refreshPD();
			for (int idc=0;idc<solution.getRouteList().size();idc++) {
				if(solution.getRouteList().get(idc).getId() == jId) {
					solution.getRouteList().get(idc).refreshPD();
					break;
				}
			}
		}
		if(pattern==4) {
			//Swap(2,1)
			//System.out.println("Swap(2,1):");
			int i = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			while(solution.getRouteList().get(i).getCityList().size()<4){
				i = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			}
			int j = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			while(i==j) {
				j = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			}
			int ki = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-3)+1);
			int kj = (int)Math.floor(Math.random()*(solution.getRouteList().get(j).getCityList().size()-2)+1);
			City cityi1 = solution.getRouteList().get(i).getCityList().get(ki);
			City cityi2 = solution.getRouteList().get(i).getCityList().get(ki+1);
			City cityj = solution.getRouteList().get(j).getCityList().get(kj);
		
			/*ShowSolution.showRoute(solution.getRouteList().get(i));
			ShowSolution.showRoute(solution.getRouteList().get(j));
			System.out.println("after localSearch: ki="+ki+"  kj="+kj);*/
			
			solution.getRouteList().get(i).getCityList().set(ki, cityj);
			solution.getRouteList().get(i).getCityList().remove(ki+1);
			solution.getRouteList().get(j).getCityList().set(kj, cityi1);
			solution.getRouteList().get(j).getCityList().add(kj+1, cityi2);
			int jId = solution.getRouteList().get(j).getId();
			solution.getRouteList().get(i).refreshPD();
			for (int idc=0;idc<solution.getRouteList().size();idc++) {
				if(solution.getRouteList().get(idc).getId() == jId) {
					solution.getRouteList().get(idc).refreshPD();
					break;
				}
			}
			
/*			ShowSolution.showRoute(solution.getRouteList().get(i));
			ShowSolution.showRoute(solution.getRouteList().get(j));
			System.out.println();*/
		}
		if(pattern==5) {
			//Swap(2,2)
			//System.out.println("Swap(2,2):");
			int i = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			while(solution.getRouteList().get(i).getCityList().size()<4){
				i = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			}
			int j = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			while(i==j||solution.getRouteList().get(j).getCityList().size()<4) {
				j = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			}
			int ki = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-3)+1);
			int kj = (int)Math.floor(Math.random()*(solution.getRouteList().get(j).getCityList().size()-3)+1);
			City cityi1 = solution.getRouteList().get(i).getCityList().get(ki);
			City cityi2 = solution.getRouteList().get(i).getCityList().get(ki+1);
			City cityj1 = solution.getRouteList().get(j).getCityList().get(kj);
			City cityj2 = solution.getRouteList().get(j).getCityList().get(kj+1);

			/*ShowSolution.showRoute(solution.getRouteList().get(i));
			ShowSolution.showRoute(solution.getRouteList().get(j));
			System.out.println("after localSearch: ki="+ki+"  kj="+kj);*/
			
			solution.getRouteList().get(i).getCityList().set(ki, cityj1);
			solution.getRouteList().get(i).getCityList().set(ki+1,cityj2);
			solution.getRouteList().get(j).getCityList().set(kj, cityi1);
			solution.getRouteList().get(j).getCityList().set(kj+1, cityi2);
			int jId = solution.getRouteList().get(j).getId();
			solution.getRouteList().get(i).refreshPD();
			for (int idc=0;idc<solution.getRouteList().size();idc++) {
				if(solution.getRouteList().get(idc).getId() == jId) {
					solution.getRouteList().get(idc).refreshPD();
					break;
				}
			}
			
		/*	ShowSolution.showRoute(solution.getRouteList().get(i));
			ShowSolution.showRoute(solution.getRouteList().get(j));
			System.out.println();*/
		}
		if(pattern==6) {
			//Cross
			//System.out.println("Cross:");
			int i = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			while(solution.getRouteList().get(i).getCityList().size()<4){
				i = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			}
			int j = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			while(i==j||solution.getRouteList().get(j).getCityList().size()<4) {
				j = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			}
			List<City> cityListi = new ArrayList<City>();
			List<City> cityListj = new ArrayList<City>();
			int ki = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-2)+1);
			int kj = (int)Math.floor(Math.random()*(solution.getRouteList().get(j).getCityList().size()-2)+1);
			int ii=ki+1;
			int jj=kj+1;

			/*ShowSolution.showRoute(solution.getRouteList().get(i));
			ShowSolution.showRoute(solution.getRouteList().get(j));
			System.out.println("after localSearch: ki="+ki+"  kj="+kj);*/
			
			while(ii<solution.getRouteList().get(i).getCityList().size()-1) {
				cityListi.add(solution.getRouteList().get(i).getCityList().get(ii));
				solution.getRouteList().get(i).getCityList().remove(ii);
			}
			while(jj<solution.getRouteList().get(j).getCityList().size()-1) {
				cityListj.add(solution.getRouteList().get(j).getCityList().get(jj));
				solution.getRouteList().get(j).getCityList().remove(jj);
			}
			for(int ci=0;ci<cityListj.size();ci++) {
				solution.getRouteList().get(i).getCityList().add(solution.getRouteList().get(i).getCityList().size()-1, cityListj.get(ci));
			}
			for(int cj=0;cj<cityListi.size();cj++) {
				solution.getRouteList().get(j).getCityList().add(solution.getRouteList().get(j).getCityList().size()-1, cityListi.get(cj));
			}
			int jId = solution.getRouteList().get(j).getId();
			solution.getRouteList().get(i).refreshPD();
			for (int idc=0;idc<solution.getRouteList().size();idc++) {
				if(solution.getRouteList().get(idc).getId() == jId) {
					solution.getRouteList().get(idc).refreshPD();
					break;
				}
			}
			
			/*ShowSolution.showRoute(solution.getRouteList().get(i));
			ShowSolution.showRoute(solution.getRouteList().get(j));			
			System.out.println();*/
		}
		
	}
	
	public void intraRouteMove(Solution solution, int pattern) {
		//intra-route movements
		//System.out.println("------------intra-route search------------");
		if(pattern==1) {
			//Or-opt
			//System.out.println("Or-opt:");
			int pat = (int)Math.floor(Math.random()*3)+1;
			if(pat==1) {
				//Or-opt(1)
				//System.out.println("Or-opt(1):");
				int i = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
				while(solution.getRouteList().get(i).getCityList().size()<4) {
					i = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
				}
				int j = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-2)+1);
				int k = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-2)+1);
				while(k==j) {
					k = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-2)+1);
				}

				/*ShowSolution.showRoute(solution.getRouteList().get(i));
				System.out.println("after localSearch: j="+j+"  k="+k);*/
				City city = solution.getRouteList().get(i).getCityList().get(j);		
				solution.getRouteList().get(i).getCityList().remove(j);
				solution.getRouteList().get(i).getCityList().add(k, city);
				solution.getRouteList().get(i).refreshPD();
				
				/*ShowSolution.showRoute(solution.getRouteList().get(i));
				System.out.println();*/
			}
			if(pat==2) {
				//Or-opt(2)
				//System.out.println("Or-opt(2):");
				int i = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
				while(solution.getRouteList().get(i).getCityList().size()<5) {
					i = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
				}
				int j = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-3)+1);
				int k = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-3)+1);
				while(k==j) {
					k = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-3)+1);
				}

				/*ShowSolution.showRoute(solution.getRouteList().get(i));
				System.out.println("after localSearch: j="+j+"  k="+k);*/
				
				List<City> cityList = new ArrayList<City>();	
				while(cityList.size()<2) {
					cityList.add(solution.getRouteList().get(i).getCityList().get(j));	
					solution.getRouteList().get(i).getCityList().remove(j);
				}
				solution.getRouteList().get(i).getCityList().add(k, cityList.get(0));
				solution.getRouteList().get(i).getCityList().add(k+1, cityList.get(1));
				solution.getRouteList().get(i).refreshPD();
				
				/*ShowSolution.showRoute(solution.getRouteList().get(i));
				System.out.println();*/
			}
			if(pat==3) {
				//Or-opt(3)
				//System.out.println("Or-opt(3):");
				int i = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
				while(solution.getRouteList().get(i).getCityList().size()<6) {
					i = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
				}
				int j = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-4)+1);
				int k = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-4)+1);
				while(k==j) {
					k = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-4)+1);
				}
				List<City> cityList = new ArrayList<City>();	
				
/*
				ShowSolution.showRoute(solution.getRouteList().get(i));
				System.out.println("after localSearch: j="+j+"  k="+k);*/
				while(cityList.size()<3) {
					cityList.add(solution.getRouteList().get(i).getCityList().get(j));	
					solution.getRouteList().get(i).getCityList().remove(j);
				}
				solution.getRouteList().get(i).getCityList().add(k, cityList.get(0));
				solution.getRouteList().get(i).getCityList().add(k+1, cityList.get(1));
				solution.getRouteList().get(i).getCityList().add(k+2, cityList.get(2));
				solution.getRouteList().get(i).refreshPD();
				
				/*ShowSolution.showRoute(solution.getRouteList().get(i));
				System.out.println();*/
			}
		}
		if(pattern==2) {
			//2-opt
			//System.out.println("2-opt:");
			int i = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			while(solution.getRouteList().get(i).getCityList().size()<6) {
				i = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			}
			int j = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-2)+1);
			int k = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-2)+1);
			while(Math.abs(j-k)<3) {
				j = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-2)+1);
				k = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-2)+1);
			}
			int minJK = Math.min(j, k);
			int maxJK = Math.max(j, k);
			
/*			ShowSolution.showRoute(solution.getRouteList().get(i));
			System.out.println("after localSearch: j="+j+"  k="+k);*/
			
			List<City> cityList = new ArrayList<City>();			
			for(int c=minJK+1;c<maxJK;c++) {
				cityList.add(solution.getRouteList().get(i).getCityList().get(c));
			}
			Collections.reverse(cityList);
			for(int c=minJK+1;c<maxJK;c++) {
				solution.getRouteList().get(i).getCityList().set(c, cityList.get(c-minJK-1));
			}
			
/*			ShowSolution.showRoute(solution.getRouteList().get(i));
			System.out.println();*/
		}
		if(pattern==3) {
			//permutation; intra-route version of Swap(1,1)
			//System.out.println("Permutation:");
			int i = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			while(solution.getRouteList().get(i).getCityList().size()<4) {
				i = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			}
			int j = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-2)+1);
			int k = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-2)+1);

			while(k==j) {
				k = (int)Math.floor(Math.random()*(solution.getRouteList().get(i).getCityList().size()-2)+1);
			}

/*			ShowSolution.showRoute(solution.getRouteList().get(i));
			System.out.println("after localSearch: j="+j+"  k="+k);*/
			
			Collections.swap(solution.getRouteList().get(i).getCityList(), j, k);
			solution.getRouteList().get(i).refreshPD();
			
/*			ShowSolution.showRoute(solution.getRouteList().get(i));
			System.out.println();*/
		}
		if(pattern==4) {
			//Reverse
			//System.out.println("Reverse:");
			int i = (int)Math.floor(Math.random()*(solution.getRouteList().size()));
			Route route = (Route)solution.getRouteList().get(i).clone();
			Collections.reverse(route.getCityList());
			route.refreshPD();
			
			/*ShowSolution.showRoute(solution.getRouteList().get(i));
			System.out.println("after localSearch:");*/
			
			if(route.getCapacityViolation()<solution.getRouteList().get(i).getCapacityViolation()) {
				solution.getRouteList().set(i, route);
			}
			
/*			ShowSolution.showRoute(solution.getRouteList().get(i));
			System.out.println();*/
		}
	}

}
